#ifndef __STRINGHELPERS__
#define __STRINGHELPERS__

#include <string>
#include <vector>
#include <cstdarg>
#include <Ice/Config.h>

namespace Xts
{

	namespace Util
	{
		// Split a string with a delimiter. NOTE: The blank space element are not removed from elems.
		// eg. Split("abc; ;edf", elems, ";") results elems contains 3 strings "abc", " " and "edf"
		void Split(const ::std::string& str, ::std::vector<::std::string>& elems, const ::std::string& delimiters = " ") ;

		// Split a string with a delimiter. NOTE: The blank space element are not removed returned elems.
		// eg. Split("abc; ;edf", ";") will return 3 strings "abc", " " and "edf"
		::std::vector<::std::string> Split(const ::std::string& str, const ::std::string& delimiters = " ") ;

		// This string converters are implemented with C++11 new functions in ::std. We implemented them here because 
		// we want to choose different implementation and pass build on different version of C++ standard.
		// Be aware that building with older VC (like VS6.0) will force you use none-C++11 feature.
		inline int Stoi( const ::std::string& str, ::std::size_t* pos = 0, int base = 10 ) ;

		inline long Stol( const ::std::string& str, ::std::size_t* pos = 0, int base = 10 ) ;

		inline long long Stoll( const ::std::string& str, ::std::size_t* pos = 0, int base = 10 ) ;

		inline float Stof( const ::std::string& str, ::std::size_t* pos = 0 ) ;

		inline double Stod( const ::std::string& str, ::std::size_t* pos = 0 ) ;

		// Handy functions for numbers convert
		inline ::std::string Itos(int n, const char* format = "%d");

		inline ::std::string Ltos(long n, const char* format = "%d");

		// TODO linux use different format %lld.
		inline ::std::string Ltos(Ice::Long n, const char* format = "%I64d");

		inline ::std::string Ftos(float f, const char* format = "%f");

		inline ::std::string Dtos(double d, const char* format = "%f");

		//this is safe and convenient but not exactly efficient
		// Return string according to your format control and args pass to the function. 
		// Format control is the same as printf
		// Throw exception if format string is NULL
		// Access violation if fmt string not match arg ptr count eg. Format("%s%s", "1234")
		inline std::string Format(const char* fmt, ...);

		inline std::string Format(const std::string fmtStr, ...);



		int Stoi( const ::std::string& str, ::std::size_t* pos /*= 0*/, int base /*= 10 */ )
		{
			return ::std::stoi(str, pos, base); //C++11
		}

		long Stol( const ::std::string& str, ::std::size_t* pos /*= 0*/, int base /*= 10 */ )
		{
			return ::std::stol(str, pos, base); //C++11
		}

		long long Stoll( const ::std::string& str, ::std::size_t* pos /*= 0*/, int base /*= 10 */ )
		{
			return ::std::stoll(str, pos, base); //C++11
		}

		float Stof( const ::std::string& str, ::std::size_t* pos /*= 0 */ )
		{
			return ::std::stof(str, pos); //C++11
		}

		double Stod( const ::std::string& str, ::std::size_t* pos /*= 0 */ )
		{
			return ::std::stod(str, pos); //C++11
		}

		::std::string Itos(int n, const char* format)
		{
			return Format(format, n);
		}

		::std::string Ltos(long n, const char* format)
		{
			return Format(format, n);
		}

		::std::string Ltos(Ice::Long n, const char* format)
		{
			return Format(format, n);
		}

		::std::string Ftos(float f, const char* format)
		{
			return Format(format, f);
		}

		::std::string Dtos(double d, const char* format)
		{
			return Format(format, d);
		}

		std::string Format(const char* fmt, ...)
		{
			if(fmt == NULL) throw "NULL format control string is not allowed!";

			char* buffer = 0;

			va_list vl;
			va_start(vl, fmt);

			//TODO Multi-platform: take care of the _vscprintf, vsnprintf_s on noe Windows platform
			//http://stackoverflow.com/questions/17351874/is-vsnprintf-s-an-appropriate-replacement-for-deprecated-vsnprintf
			int size = _vscprintf(fmt, vl);
			buffer = new char[++size];

			int nsize = vsnprintf_s(buffer, size, _TRUNCATE, fmt, vl);

			_ASSERT(nsize != -1);
			if(nsize == -1 )
			{// we should never here
				throw "Should never be here!";
			}

			std::string ret(buffer);
			va_end(vl);

			delete[] buffer;

			return std::move(ret);
		}

		std::string Format(const std::string fmtStr, ...)
		{
			va_list vl;

			va_start(vl, fmtStr);				
			std::string ret = Format(fmtStr.c_str(), vl);			
			va_end(vl);

			return std::move(ret);// C++11
		}
	}


}//Xts
#endif

